﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using IEx.Common;
using IEx.Model.Partials;
using IEx.Utilities;

namespace IEx.ParserBuilder.FinanceReport
{
    public class HKExNewsReportParser : IHtmlParser
    {
        public virtual void Parse(SourceItem item, string html, Action<Announcement> attachResultItem, Action<SourceItem> attachNewItemSource)
        {
            // Response Html of daily url has different structure with historical url
            // Detect the current url is daily and swith to daily parser
            if (!string.IsNullOrEmpty(item.DailyUrl) && item.Url.Equals(item.DailyUrl, StringComparison.OrdinalIgnoreCase))
            {
                this.DailyParser(item, html, attachResultItem);
                return;
            }

            try
            {
                string gridId = "ctl00_gvMain";
                int indexTable = html.IndexOf(gridId);
                string strResult = indexTable > 0 ? html.Substring(indexTable) : string.Empty;
                int indexThead = strResult.IndexOf("</th>");
                strResult = indexThead > 0 ? strResult.Substring(indexThead) : string.Empty;
                int indexFooter = strResult.IndexOf("<tr class=\"footerStyle\">");
                string htmlFooter = indexFooter > 0 ? strResult.Substring(indexFooter) : string.Empty;
                strResult = !string.IsNullOrEmpty(htmlFooter) ? strResult.Replace(htmlFooter, string.Empty) : strResult;
                // the need of detectedAnnouncements is to avoid inserting new announcement immediately into download queue 
                // while we don't know whether has an error in parsing or not
                List<Announcement> detectedAnnouncements = new List<Announcement>();
                if (!string.IsNullOrEmpty(strResult))
                {
                    Regex regexTr = RegexUtility.CreateRegexByHtmlTag("tr");
                    MatchCollection matchcollectionTr = regexTr.Matches(strResult);
                    Regex regexTd = new Regex("<td [^>]*?>.*?</td>");
                    for (int i = 0; i < matchcollectionTr.Count; i++)
                    {
                        string trContent = matchcollectionTr[i].Value;
                        trContent = string.Join(" ", Regex.Split(trContent, @"(?:\r\n|\n|\r)"));

                        string dateTime = string.Empty;
                        string pressreleaseType = string.Empty;
                        string title = string.Empty;
                        string hrefValue = string.Empty;

                        MatchCollection collectionTd = regexTd.Matches(trContent);
                        //loop td tag to get string
                        for (int j = 0; j < collectionTd.Count; j++)
                        {
                            string tdContent = collectionTd[j].Value;
                            if (j == 0)
                            {
                                //get date time value
                                string tdDateTime = RegexUtility.ExtractHtmlContent("td", tdContent);
                                dateTime = RegexUtility.ExtractHtmlContent("span", tdDateTime);
                            }
                            if (j == 3)
                            {
                                //get pressrelease type, title, href
                                string tdMessage = RegexUtility.ExtractHtmlContent("td", tdContent);
                                string spanPressreleaseType = RegexUtility.ExtractHtmlContentByPattern(tdMessage, "<(span) id=\".*?lbShortText\">.*?</(span)>").Trim();
                                string moreInfo = RegexUtility.ExtractHyperlink(spanPressreleaseType);
                                pressreleaseType = !string.IsNullOrEmpty(moreInfo) ? GetFullPressrelaseType(item, moreInfo) : RegexUtility.ExtractHtmlContent("span", spanPressreleaseType).Trim();
                                title = RegexUtility.ExtractHtmlContent("a", tdMessage);
                                hrefValue = RegexUtility.ExtractHyperlink(tdMessage);
                            }
                        }
                        if (dateTime.Contains("<br>"))
                            dateTime = dateTime.Replace("<br>", " ");

                        if (pressreleaseType.Contains("<br>"))
                            pressreleaseType = pressreleaseType.Replace("<br>", " ");

                        string linkValue = string.Empty;

                        if (hrefValue.StartsWith("http://") || hrefValue.StartsWith("https://"))
                        {
                            linkValue = hrefValue.Trim();
                        }
                        else
                        {
                            linkValue = "http://" + Utility.GetDomainName(item.Url) + hrefValue.Trim();
                        }

                        DateTime dateTimeValue = Utility.ConvertToDateTimeObject(dateTime, item.DateTimeFormat);

                        title = RegexUtility.ExtractTextFromHtmlTag(title).Trim();

                        //Checking extension's file is HTML then we request to server get HTML content 
                        // After that analysis content HTML detect PDF links.
                        List<string> linkDownloads = new List<string>();
                        Uri uri = new Uri(linkValue);
                        FileInfo fileInfo = new FileInfo(uri.AbsolutePath);
                        var extFile = fileInfo.Extension;
                        string htmlContent = string.Empty;
                        if (extFile.Trim().ToLower() == ".htm")
                        {
                            linkDownloads = RegexUtility.ExtractMultipleLinkDownload(linkValue, ref htmlContent);
                            if (linkDownloads.Count == 0)
                            {
                                linkDownloads.Add(linkValue);
                            }
                        }
                        else
                        {
                            linkDownloads.Add(linkValue);
                        }

                        if (!string.IsNullOrEmpty(title) && dateTimeValue.CompareTo(DateTime.MinValue) != 0)
                        {
                            Announcement announcement = new Announcement()
                            {
                                Attachment = false,
                                SourceCode = item.SourceCode,
                                DateTime = dateTimeValue,
                                DateNumberic =
                                    long.Parse(
                                        dateTimeValue.ToString("yyyyMMddHHmmss")),
                                InsertedDate = DateTime.Now,
                                LangId = item.LangId,
                                Message = htmlContent,                               
                                SourceId = item.SourceId,                                
                                Title = title,
                                PressrelaseType = pressreleaseType.Trim(),                                
                                AttachmentLinks = linkDownloads
                            };

                            detectedAnnouncements.Add(announcement);
                        }
                    }
                }
                // check if has next page 
                // next page counts as a new request, so it needed insert into request queue
                if (CheckNextPage(html))
                {
                    SourceItem nItem = new SourceItem(item.Url, item.LangId, item.SourceCode, item.SearchCode, item.SourceId, item.DateTimeFormat);
                    if (!string.IsNullOrEmpty(item.RequestBuilderType))
                        nItem.RequestBuilderType = item.RequestBuilderType;

                    if (!string.IsNullOrEmpty(item.HtmlParserType))
                        nItem.HtmlParserType = item.HtmlParserType;

                    nItem.PrevResponseHtml = html;
                    attachNewItemSource(nItem);
                }

                // insert into download queue when no error in parsing
                foreach (Announcement ann in detectedAnnouncements)
                {
                    attachResultItem(ann);
                }

                // if this request is fail request in previous scanning, 
                // remove it when success in current scanning
                if (item.FailId > 0)
                    Utility.DeleteFailRequests(item.FailId);
            }
            catch (Exception ex)
            {
                // if has an error, save fail request to next time scanning
                if (item.FailId == 0)
                {
                    item.FailId = DateTime.Now.Ticks;
                    Utility.SaveFailRequests(item);
                }

                // then write log
                string message = string.Format(@"
            Company code:   {0}
            HTML Parsing:   Fail
            Request URL:    {1}
            Search key:     {2}", item.SourceCode, item.Url, item.SearchCode);
                Logger.WriteError(message, ex);
            }
        }

        private void DailyParser(SourceItem item, string html, Action<Announcement> attachResultItem)
        {
            try
            {
                string startIndexContent = "<!--START INDEX GENERATION-->";
                string endIndexContent = "<!--END INDEX GENERATION-->";

                int startIndex = html.IndexOf(startIndexContent);
                int endIndex = html.IndexOf(endIndexContent);
                string startTempHtml = html.Substring(startIndex);
                string endTempHtml = html.Substring(endIndex);

                string htmlResutl = startTempHtml.Replace(endTempHtml, string.Empty);

                List<Announcement> detectedAnnouncements = new List<Announcement>();

                if (!string.IsNullOrEmpty(htmlResutl))
                {
                    Regex regexTr = RegexUtility.CreateRegexByHtmlTag("tr");
                    MatchCollection matchcollectionTr = regexTr.Matches(htmlResutl);
                    Regex regexTd = new Regex("<td[^>]*?>.*?</td>");
                    for (int i = 0; i < matchcollectionTr.Count; i++)
                    {
                        string trContent = matchcollectionTr[i].Value;
                        trContent = string.Join(" ", Regex.Split(trContent, @"(?:\r\n|\n|\r)"));

                        string dateTime = string.Empty;
                        string searchCode = string.Empty;
                        string pressreleaseType = string.Empty;
                        string title = string.Empty;
                        string hrefValue = string.Empty;

                        MatchCollection collectionTd = regexTd.Matches(trContent);
                        //loop td tag to get string
                        for (int j = 0; j < collectionTd.Count; j++)
                        {
                            string tdContent = collectionTd[j].Value;
                            if (j == 0)
                            {
                                //get date time value
                                string tdDateTime = RegexUtility.ExtractHtmlContent("td", tdContent);
                                dateTime = Regex.Replace(tdDateTime, @"<img\s[^>]*>(?:\s*?</img>)?", string.Empty,
                                                         RegexOptions.IgnoreCase);
                                dateTime = dateTime.Replace("<br>", " ");
                            }

                            if (j == 1)
                            {
                                searchCode = RegexUtility.ExtractHtmlContent("td", tdContent);
                            }

                            if (j == 3)
                            {
                                string tdMessage = RegexUtility.ExtractHtmlContent("td", tdContent);
                                string divPressreleaseType =
                                    RegexUtility.ExtractHtmlContent("div", tdMessage).Replace("<br>", string.Empty).Trim
                                        ();
                                string moreInfo = RegexUtility.ExtractHyperlink(divPressreleaseType);
                                pressreleaseType = !string.IsNullOrEmpty(moreInfo)
                                                       ? GetFullPressrelaseType(item, moreInfo)
                                                       : divPressreleaseType;
                                title = RegexUtility.ExtractHtmlContent("a", tdMessage);
                                hrefValue = RegexUtility.ExtractHyperlink(tdMessage);
                            }
                        }

                        // check isexist company code in our customers
                        bool isExisted = item.SearchCode.Equals(searchCode, StringComparison.OrdinalIgnoreCase);
                        if (isExisted)
                        {
                            string sourceCode = string.Empty;
                            int langId = 0;
                            int sourceId = 0;
                            string dateTimeFormat = string.Empty;
                            string requestUrl = string.Empty;

                            sourceCode = item.SourceCode;
                            langId = item.LangId;
                            sourceId = item.SourceId;
                            dateTimeFormat = item.DateTimeFormat;
                            requestUrl = item.DailyUrl;

                            DateTime dateTimeValue = Utility.ConvertToDateTimeObject(dateTime, dateTimeFormat);
                            string linkValue = string.Empty;

                            if (hrefValue.StartsWith("http://") || hrefValue.StartsWith("https://"))
                            {
                                linkValue = hrefValue.Trim();
                            }
                            else
                            {
                                linkValue = "http://" + Utility.GetDomainName(requestUrl) + hrefValue.Trim();
                            }

                            //Checking extension's file is HTML then we request to server get HTML content 
                            // After that analysis content HTML detect PDF links.
                            List<string> linkDownloads = new List<string>();
                            Uri uri = new Uri(linkValue);
                            FileInfo fileInfo = new FileInfo(uri.AbsolutePath);
                            var extFile = fileInfo.Extension;
                            string htmlContent = string.Empty;
                            if (extFile.Trim().ToLower() == ".htm")
                            {
                                linkDownloads = RegexUtility.ExtractMultipleLinkDownload(linkValue, ref htmlContent);
                                if (linkDownloads.Count == 0)
                                {
                                    linkDownloads.Add(linkValue);
                                }
                            }
                            else
                            {
                                linkDownloads.Add(linkValue);
                            }

                            if (!string.IsNullOrEmpty(title) && dateTimeValue.CompareTo(DateTime.MinValue) != 0)
                            {
                                Announcement announcement = new Announcement()
                                {
                                    Attachment = false,
                                    SourceCode = sourceCode,
                                    DateTime = dateTimeValue,
                                    DateNumberic =
                                        long.Parse(
                                            dateTimeValue.ToString("yyyyMMddHHmmss")),                                    
                                    InsertedDate = DateTime.Now,
                                    LangId = langId,
                                    Message = htmlContent,                                                                        
                                    SourceId = sourceId,                                    
                                    Title = title,
                                    //PressrelaseType = pressreleaseType.Trim(),                                    
                                    AttachmentLinks = linkDownloads
                                };

                                detectedAnnouncements.Add(announcement);
                            }

                            // Exit the loop
                            //break;
                        }
                    }
                }

                // insert into download queue when no error in parsing
                foreach (Announcement ann in detectedAnnouncements)
                {
                    attachResultItem(ann);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError("ERROR: ", ex);
            }
        }

        protected static bool CheckNextPage(string response)
        {
            return response.Contains("ctl00$gvMain$ctl01$btnNext");
        }

        protected string GetFullPressrelaseType(SourceItem sourceItem, string moreInfo)
        {
            // get request url
            string companyCode = string.Empty;
            string linkMoreInfo = string.Empty;
            string resultContent = string.Empty;
            if (!string.IsNullOrEmpty(sourceItem.DailyUrl) && sourceItem.Url.Equals(sourceItem.DailyUrl, StringComparison.OrdinalIgnoreCase))
            {
                string requestUrl = string.Empty;
                requestUrl = sourceItem.DailyUrl;

                if (moreInfo.StartsWith("http://") || moreInfo.StartsWith("https://"))
                {
                    linkMoreInfo = moreInfo.Trim();
                }
                else
                {
                    linkMoreInfo = "http://" + Utility.GetDomainName(requestUrl) + moreInfo.Trim();
                }
            }
            else
            {
                string requestUrl = string.Empty;
                requestUrl = sourceItem.Url;

                if (moreInfo.StartsWith("http://") || moreInfo.StartsWith("https://"))
                {
                    linkMoreInfo = moreInfo.Trim();
                }
                else
                {
                    int lastPositionRequest = requestUrl.LastIndexOf('/') + 1;
                    string subRequest = requestUrl.Substring(0, lastPositionRequest) + moreInfo.Trim();
                    linkMoreInfo = subRequest;
                }
            }

            // request
            string htmlContentMoreInfo = GetWebResponse(linkMoreInfo, sourceItem.SourceCode);
            resultContent = RegexUtility.ExtractTextFromHtmlTag(htmlContentMoreInfo);
            return resultContent.Trim();
        }

        private string GetWebResponse(string RequestUrl, string company)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(RequestUrl);
                //Set timeout for request
                int requestTimeout = 100000;
                int.TryParse(ConfigurationManager.AppSettings["MaxRequestTimeout"], out requestTimeout);
                request.Timeout = requestTimeout;

                return (new WebResponseEncoding(request)).GetResponse();
            }
            catch (Exception ex)
            {
                // write log
                string message = string.Format(@"
    Company: {0}
    Request fail: {1}
    at get more content for Pressrelase Type: {2}", company, RequestUrl, string.Empty);
                Logger.WriteError(message, ex);

                return string.Empty;
            }
        }
    }

    public class FinanceReportParserUpdate : HKExNewsReportParser
    {
        public override void Parse(SourceItem item, string html, Action<Announcement> attachResultItem, Action<SourceItem> attachNewItemSource)
        {
            try
            {
                string gridId = "ctl00_gvMain";
                int indexTable = html.IndexOf(gridId);
                string strResult = indexTable > 0 ? html.Substring(indexTable) : string.Empty;
                int indexThead = strResult.IndexOf("</th>");
                strResult = indexThead > 0 ? strResult.Substring(indexThead) : string.Empty;
                int indexFooter = strResult.IndexOf("<tr class=\"footerStyle\">");
                string htmlFooter = indexFooter > 0 ? strResult.Substring(indexFooter) : string.Empty;
                strResult = !string.IsNullOrEmpty(htmlFooter) ? strResult.Replace(htmlFooter, string.Empty) : strResult;
                // the need of detectedAnnouncements is to avoid inserting new announcement immediately into download queue 
                // while we don't know whether has an error in parsing or not
                List<Announcement> detectedAnnouncements = new List<Announcement>();
                if (!string.IsNullOrEmpty(strResult))
                {
                    Regex regexTr = RegexUtility.CreateRegexByHtmlTag("tr");
                    MatchCollection matchcollectionTr = regexTr.Matches(strResult);
                    Regex regexTd = new Regex("<td [^>]*?>.*?</td>");
                    for (int i = 0; i < matchcollectionTr.Count; i++)
                    {
                        string trContent = matchcollectionTr[i].Value;
                        trContent = string.Join(" ", Regex.Split(trContent, @"(?:\r\n|\n|\r)"));

                        string dateTime = string.Empty;
                        string pressreleaseType = string.Empty;
                        string title = string.Empty;
                        string hrefValue = string.Empty;

                        MatchCollection collectionTd = regexTd.Matches(trContent);
                        //loop td tag to get string
                        for (int j = 0; j < collectionTd.Count; j++)
                        {
                            string tdContent = collectionTd[j].Value;
                            if (j == 0)
                            {
                                //get date time value
                                string tdDateTime = RegexUtility.ExtractHtmlContent("td", tdContent);
                                dateTime = RegexUtility.ExtractHtmlContent("span", tdDateTime);
                            }
                            if (j == 3)
                            {
                                //get pressrelease type, title, href
                                string tdMessage = RegexUtility.ExtractHtmlContent("td", tdContent);
                                string spanPressreleaseType = RegexUtility.ExtractHtmlContentByPattern(tdMessage, "<(span) id=\".*?lbShortText\">.*?</(span)>").Trim();
                                string moreInfo = RegexUtility.ExtractHyperlink(spanPressreleaseType);
                                pressreleaseType = !string.IsNullOrEmpty(moreInfo) ? GetFullPressrelaseType(item, moreInfo) : RegexUtility.ExtractHtmlContent("span", spanPressreleaseType).Trim();
                                title = RegexUtility.ExtractHtmlContent("a", tdMessage);
                                hrefValue = RegexUtility.ExtractHyperlink(tdMessage);
                            }
                        }
                        if (dateTime.Contains("<br>"))
                            dateTime = dateTime.Replace("<br>", " ");

                        if (pressreleaseType.Contains("<br>"))
                            pressreleaseType = pressreleaseType.Replace("<br>", " ");

                        string linkValue = string.Empty;

                        if (hrefValue.StartsWith("http://") || hrefValue.StartsWith("https://"))
                        {
                            linkValue = hrefValue.Trim();
                        }
                        else
                        {
                            linkValue = "http://" + Utility.GetDomainName(item.Url) + hrefValue.Trim();
                        }

                        DateTime dateTimeValue = Utility.ConvertToDateTimeObject(dateTime, item.DateTimeFormat);

                        title = RegexUtility.ExtractTextFromHtmlTag(title).Trim();

                        //Checking extension's file is HTML then we request to server get HTML content 
                        // After that analysis content HTML detect PDF links.
                        List<string> linkDownloads = new List<string>();
                        Uri uri = new Uri(linkValue);
                        FileInfo fileInfo = new FileInfo(uri.AbsolutePath);
                        var extFile = fileInfo.Extension;
                        string htmlContent = string.Empty;
                        if (extFile.Trim().ToLower() == ".htm")
                        {
                            linkDownloads = RegexUtility.ExtractMultipleLinkDownload(linkValue, ref htmlContent);
                        }
                        else
                        {
                            linkDownloads.Add(linkValue);
                        }
                        if (!string.IsNullOrEmpty(title) && dateTimeValue.CompareTo(DateTime.MinValue) != 0)
                        {
                            Announcement announcement = new Announcement()
                            {
                                Attachment = false,
                                SourceCode = item.SourceCode,
                                DateTime = dateTimeValue,
                                DateNumberic =
                                    long.Parse(
                                        dateTimeValue.ToString("yyyyMMddHHmmss")),
                                InsertedDate = DateTime.Now,
                                LangId = item.LangId,
                                Message = htmlContent,                                
                                SourceId = item.SourceId,
                                Title = title,
                                //PressrelaseType = pressreleaseType.Trim(),                                
                                AttachmentLinks = linkDownloads,
                                Updated = true // Force update pressrelease only
                            };

                            detectedAnnouncements.Add(announcement);
                        }
                    }
                }
                // check if has next page 
                // next page counts as a new request, so it needed insert into request queue
                if (CheckNextPage(html))
                {
                    SourceItem nItem = new SourceItemUpdate()
                    {
                        Url = item.Url,
                        LangId = item.LangId,
                        FilterLanguageID = (item as SourceItemUpdate).FilterLanguageID,
                        SourceCode = item.SourceCode,
                        SourceId = item.SourceId,
                        SearchCode = item.SearchCode,
                        Category = item.Category,
                        DateTimeFormat = item.DateTimeFormat,
                        DailyUrl = item.DailyUrl,
                        FailId = item.FailId,
                        DateFrom = (item as SourceItemUpdate).DateFrom,
                        DateTo = (item as SourceItemUpdate).DateTo
                    };
                    if (!string.IsNullOrEmpty(item.RequestBuilderType))
                        nItem.RequestBuilderType = item.RequestBuilderType;

                    if (!string.IsNullOrEmpty(item.HtmlParserType))
                        nItem.HtmlParserType = item.HtmlParserType;

                    nItem.PrevResponseHtml = html;
                    attachNewItemSource(nItem);
                }

                // insert into download queue when no error in parsing
                foreach (Announcement ann in detectedAnnouncements)
                {
                    attachResultItem(ann);
                }

                // if this request is fail request in previous scanning, 
                // remove it when success in current scanning
                if (item.FailId > 0)
                    Utility.DeleteFailRequests(item.FailId);
            }
            catch (Exception ex)
            {
                // Left it blank
            }
        }
    }
}
